package org.smartboot.pass;

import com.moandjiezana.toml.Toml;
import org.smartboot.http.common.enums.HeaderNameEnum;
import org.smartboot.http.common.enums.HttpStatus;
import org.smartboot.http.server.HttpBootstrap;
import org.smartboot.http.server.HttpRequest;
import org.smartboot.http.server.HttpResponse;
import org.smartboot.http.server.HttpServerHandler;
import org.smartboot.http.server.handler.HttpStaticResourceHandler;
import org.smartboot.http.server.impl.Request;
import org.smartboot.pass.config.HttpServer;
import org.smartboot.pass.config.PassConfig;
import org.smartboot.socket.enhance.EnhanceAsynchronousChannelProvider;

import java.io.File;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.AsynchronousChannelGroup;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ThreadFactory;
import java.util.stream.Collectors;

/**
 * @author 三刀（zhengjunweimail@163.com）
 * @version V1.0 , 2021/7/9
 */
public class BootStrap {
    private static final String BANNER = "\n" +
            " .----------------.  .----------------.  .----------------.  .----------------. \n" +
            "| .--------------. || .--------------. || .--------------. || .--------------. |\n" +
            "| |   ______     | || |      __      | || |    _______   | || |    _______   | |\n" +
            "| |  |_   __ \\   | || |     /  \\     | || |   /  ___  |  | || |   /  ___  |  | |\n" +
            "| |    | |__) |  | || |    / /\\ \\    | || |  |  (__ \\_|  | || |  |  (__ \\_|  | |\n" +
            "| |    |  ___/   | || |   / ____ \\   | || |   '.___`-.   | || |   '.___`-.   | |\n" +
            "| |   _| |_      | || | _/ /    \\ \\_ | || |  |`\\____) |  | || |  |`\\____) |  | |\n" +
            "| |  |_____|     | || ||____|  |____|| || |  |_______.'  | || |  |_______.'  | |\n" +
            "| |              | || |              | || |              | || |              | |\n" +
            "| '--------------' || '--------------' || '--------------' || '--------------' |\n" +
            " '----------------'  '----------------'  '----------------'  '----------------' \n";
    private static final String VERSION = "0.1";
    private static Config config;

    private static final HttpServerHandler DEFAULT_HANDLER = new HttpServerHandler() {
        private final byte[] bytes = "not found".getBytes();

        @Override
        public void handle(HttpRequest request, HttpResponse response) throws IOException {
            response.setHttpStatus(HttpStatus.NOT_FOUND);
            response.setContentLength(bytes.length);
            response.getOutputStream().write(bytes);
        }
    };

    public static void main(String[] args) throws IOException {
        System.out.println(BANNER);
        System.out.println(":: PASS ::(" + VERSION + ")");
        String config = System.getProperty("conf", "/Users/zhengjw22mac123/IdeaProjects/edge-proxy/conf/pass.toml");
        Toml toml = new Toml();
        toml.read(new File(config));
        PassConfig passConfig = toml.to(PassConfig.class);

        AsynchronousChannelGroup asynchronousChannelGroup = new EnhanceAsynchronousChannelProvider(false).openAsynchronousChannelGroup(passConfig.getCoreThread(), new ThreadFactory() {
            int i;

            @Override
            public Thread newThread(Runnable r) {
                return new Thread(r, "pass-" + (++i));
            }
        });

        passConfig.getHttp().getServer().stream().collect(Collectors.groupingBy(HttpServer::getPort, Collectors.toList())).forEach((port, list) -> {
            list.stream().collect(Collectors.groupingBy(HttpServer::getIp, Collectors.toList())).forEach((ip, servers) -> {
                HttpBootstrap bootstrap = new HttpBootstrap();
                bootstrap.setPort(port);
                bootstrap.configuration().host(ip);
                bootstrap.configuration().group(asynchronousChannelGroup).bannerEnabled(false);
                //多域名模式
                Map<String, HttpServerHandler> handlers = new HashMap<>();
                servers.forEach(httpServer -> {
                    if (httpServer.getServerName() == null) {
                        httpServer.setServerName("");
                    }
                    handlers.put(httpServer.getServerName(), getRouteHandler(httpServer));
                });
                HttpServerHandler serverHandler = new HttpServerHandler() {
                    @Override
                    public void onHeaderComplete(Request request) throws IOException {
                        String host = request.getHeader(HeaderNameEnum.HOST.getName());
                        HttpServerHandler serverHandler = handlers.get(host);
                        if (serverHandler == null) {
                            serverHandler = handlers.get("");
                        }
                        if (serverHandler != null) {
                            serverHandler.onHeaderComplete(request);
                        }
                    }

                    @Override
                    public void handle(HttpRequest request, HttpResponse response) throws IOException {
                        DEFAULT_HANDLER.handle(request, response);
                    }
                };
                bootstrap.httpHandler(serverHandler);
                bootstrap.start();
            });

        });
    }

    private static HttpRouteHandler getRouteHandler(HttpServer httpServer) {
        HttpRouteHandler routeHandler = new HttpRouteHandler();
        httpServer.getLocation().forEach(location -> {
            if (location.isProxy()) {
                routeHandler.route(location.getLocation(), new HttpServerHandler() {
                    private final Map<Request, ProxyConnectionServerHandler> map = new ConcurrentHashMap<>();

                    {
                        new Thread() {
                            @Override
                            public void run() {
                                while (true) {
                                    System.out.println("Connections: " + map.size());
                                    try {
                                        Thread.sleep(1000);
                                    } catch (InterruptedException e) {
                                        e.printStackTrace();
                                    }
                                }
                            }
                        }.start();
                    }

                    @Override
                    public boolean onBodyStream(ByteBuffer buffer, Request request) {
                        return map.get(request).onBodyStream(buffer, request);
                    }

                    @Override
                    public void onClose(Request request) {
                        System.out.println("close: " + request.getRequestURI());
                        map.remove(request).onClose(request);
                    }

                    @Override
                    public void onHeaderComplete(Request request) throws IOException {
                        ProxyConnectionServerHandler proxyHttpLifecycle = new ProxyConnectionServerHandler(config);
                        map.put(request, proxyHttpLifecycle);
                        proxyHttpLifecycle.onHeaderComplete(request);
                    }

                    @Override
                    public void handle(HttpRequest request, HttpResponse response) throws IOException {
                        System.out.println("hahah");
                    }
                });
            } else {
                //静态服务
                routeHandler.route(location.getLocation(), new HttpStaticResourceHandler(location.getRoot()));
            }
        });
        return routeHandler;
    }
}
